package com.yonyougov.devops.cruxcisupport.rancher;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.yonyougov.devops.cruxcisupport.rancher.cluster.KubeApi;
import com.yonyougov.devops.cruxcisupport.rancher.cluster.RancherKubernetesEngineConfig;
import com.yonyougov.devops.cruxcisupport.rancher.cluster.RhCluster;
import com.yonyougov.devops.cruxcisupport.rancher.cluster.Services;
import com.yonyougov.devops.cruxcisupport.rancher.namespace.RhNameSpace;
import com.yonyougov.devops.cruxcisupport.rancher.response.ClusterRegistrationTokenResponse;
import com.yonyougov.devops.cruxcisupport.rancher.response.DeploymentResponse;
import com.yonyougov.devops.cruxcisupport.rancher.response.ProjectsResponse;
import com.yonyougov.devops.cruxcisupport.rancher.service.RhNameSpaceDto;
import com.yonyougov.devops.cruxcisupport.rancher.service.RhService;
import com.yonyougov.devops.cruxcisupport.rancher.vo.ClusterRegistrationToken;
import com.yonyougov.devops.cruxcisupport.rancher.vo.CreatePodRequestVo;
import com.yonyougov.devops.cruxcisupport.rancher.vo.RhDeployment;
import com.yonyougov.devops.cruxcisupport.rancher.vo.RhProject;
import com.yonyougov.devops.cruxcisupport.util.DateUtils;
import com.yonyougov.devops.cruxcisupport.util.HttpUtils;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Component
public class RancherDaoImpl implements RancherDao {
    @Value("${rh.bear-token}")
    private String bearToken;
    @Value("${rh.api}")
    private String rhApi;
    @Value("${imagePrefix}")
    private String imagePrefix;
    private final ObjectMapper objectMapper;

    public RancherDaoImpl(ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
    }

    @Override
    public RhProject getProject(String envName) {
        Map<String, String> map = new HashMap<>();
        map.put("Authorization", "Bearer " + bearToken);
        map.put("Context-Type", "application/json");
        String url = rhApi + "/projects";
        ResponseEntity<ProjectsResponse> responseEntity = HttpUtils.get(url, map, ProjectsResponse.class);
        if (responseEntity.getStatusCodeValue() != 200) {
            return null;
        }
        List<RhProject> collect = responseEntity.getBody().getData()
                .stream()
                .filter(rhProject -> envName.equals(rhProject.getName()))
                .collect(Collectors.toList());
        if (collect.size() > 0) {
            return collect.get(0);
        }
        return null;
    }

    @Override
    public RhDeployment getDeployment(String id, String appName) {
        String url = rhApi + "/projects/" + id + "/deployments";
        Map<String, String> header = new HashMap<>();
        header.put("Authorization", "Bearer " + bearToken);
        header.put("Context-Type", "application/json");
        ResponseEntity<DeploymentResponse> responseEntity = HttpUtils.get(url, header, DeploymentResponse.class);
        if (responseEntity.getStatusCodeValue() != 200) {
            log.info("get deployment fail");
            return null;
        }
        List<RhDeployment> rhDeployments = responseEntity.getBody().getData()
                .stream()
                .filter(rhDeployment -> appName.equals(rhDeployment.getName()))
                .collect(Collectors.toList());
        if (rhDeployments.size() > 0) {
            return rhDeployments.get(0);
        }
        return null;
    }


    @Override
    @SneakyThrows
    public boolean createPod(String id, CreatePodRequestVo createPodRequestVo) {
        String envName = createPodRequestVo.getEnvName();
        String appName = createPodRequestVo.getAppName();
        String image = createPodRequestVo.getImage();
        String healthCheckPath = createPodRequestVo.getHealthCheckPath();
        String realImage = "";
        String packageVersion = createPodRequestVo.getPackageVersion();
        if (StringUtils.isNotBlank(image)) {
            realImage = image;
        }
        if (StringUtils.isNotBlank(packageVersion)) {
            realImage = imagePrefix + appName + ":" + packageVersion;
        }
        Integer instance = createPodRequestVo.getInstance();
        if (null == instance) {
            instance = 1;
        }
        Pod pod = new Pod();
        pod.setNamespaceId(envName);
        pod.setName(appName);
        pod.setScale(instance);

        //标签 用于调度
        Map<String, String> labels = pod.getLabels();
        labels.put("app", appName);

        List<Container> containers = pod.getContainers();
        Container container = new Container();
        container.setNamespaceId(envName);
        container.setName(appName);
        container.setImage(realImage);

        //环境变量
        Map<String, String> environment = createPodRequestVo.getEnvironment();
        if (null != environment && environment.size() > 0) {
            container.setEnvironment(environment);
        }

        //环境变量资源文件
        List<Map<String, String>> environmentFroms = container.getEnvironmentFrom();
        Map<String, String> environmentFrom = new HashMap<>();
        environmentFrom.put("source", "configMap");
        environmentFrom.put("sourceKey", null);
        environmentFrom.put("sourceName", "fap-env");
        environmentFroms.add(environmentFrom);

        //健康检查
        if (StringUtils.isNotBlank(healthCheckPath)) {
            ReadinessProbe readinessProbe = new ReadinessProbe();
            readinessProbe.setPath(healthCheckPath);
            HashMap<String, String> httpHeaders = readinessProbe.getHttpHeaders();
            httpHeaders.put("name", "Health-Check");
            httpHeaders.put("value", "OK");
            LivenessProbe livenessProbe = new LivenessProbe();
            livenessProbe.setPath(healthCheckPath);
            livenessProbe.setHttpHeaders(httpHeaders);
            container.setReadinessProbe(readinessProbe);
            container.setLivenessProbe(livenessProbe);
        }
        //卷挂载信息
        List<VolumeMount> volumeMounts = container.getVolumeMounts();
        VolumeMount volumeMount = new VolumeMount();
        volumeMount.setName("host-time");
        volumeMount.setMountPath("/etc/localtime");
        volumeMounts.add(volumeMount);

        containers.add(container);

        //数据卷信息
        List<Volume> volumes = pod.getVolumes();
        Volume volume = new Volume();
        volume.setName("host-time");
        Map<String, String> hostPath = volume.getHostPath();
        hostPath.put("type", "hostPathVolumeSource");
        hostPath.put("kind", null);
        hostPath.put("path", "/etc/localtime");
        volumes.add(volume);

        Map<String, String> annotations = pod.getAnnotations();
        annotations.put("cattle.io/timestamp", DateUtils.parseDate(new Date(), "yyyy-MM-dd'T'HH:mm:ss'Z'"));

        String podJsonString = objectMapper.writeValueAsString(pod);
        log.info("podJsonString is : {}", podJsonString);
        String createPodUrl = rhApi + "/projects/" + id + "/workload";
        Map<String, String> header = new HashMap<>();
        header.put("Authorization", "Bearer " + bearToken);
        header.put("Context-Type", "application/json");
        ResponseEntity<String> podResponseEntity = HttpUtils.postWithParams(createPodUrl, header, podJsonString, String.class);
        if (podResponseEntity.getStatusCodeValue() != 201) {
            return false;
        }
        return true;
    }

    @Override
    public void deletePod(String nameSpace, String appName, String id) {
        String url = rhApi + "/projects/" + id + "/workload/deployment:" + nameSpace + ":" + appName;
        Map<String, String> header = new HashMap<>();
        header.put("Authorization", "Bearer " + bearToken);
        HttpUtils.delete(url, header);
    }

    @Override
    @SneakyThrows
    public void createPodService(String id, CreatePodRequestVo createPodRequestVo, RhNameSpace rhNameSpace) {
        RhNameSpaceDto rhNameSpaceDto = new RhNameSpaceDto();
        BeanUtils.copyProperties(rhNameSpace, rhNameSpaceDto);
        rhNameSpaceDto.setActionLinks(rhNameSpace.getActions());

        RhService rhService = new RhService();
        rhService.setNamespaceId(createPodRequestVo.getEnvName());
        rhService.setName(createPodRequestVo.getAppName() + "-svc");
        Map<String, String> selector = rhService.getSelector();
        selector.put("app", createPodRequestVo.getAppName());
        rhService.setPorts(createPodRequestVo.getPorts());
        rhService.setNameSpace(rhNameSpaceDto);
        ObjectMapper objectMapper = new ObjectMapper();
        String rhServiceRequestJsonStr = objectMapper.writeValueAsString(rhService);
        log.debug("rhServiceRequestJsonStr is : {} ", rhServiceRequestJsonStr);
        String url = rhApi + "/projects/" + id + "/service";
        Map<String, String> header = new HashMap<>();
        header.put("Authorization", "Bearer " + bearToken);
        header.put("Context-Type", "application/json");
        HttpUtils.postWithParams(url, header, rhServiceRequestJsonStr, String.class);
    }

    @Override
    public void deleteService(String id, String nameSpace, String serviceName) {
        String url = rhApi + "/project/" + id + "/services/" + nameSpace + ":" + serviceName;
        Map<String, String> header = new HashMap<>();
        header.put("Authorization", "Bearer " + bearToken);
        HttpUtils.delete(url, header);
    }

    @Override
    public RhNameSpace getRhNameSpace(String clusterId, String nameSpace) {
        String url = rhApi + "/cluster/" + clusterId + "/namespaces/" + nameSpace;
        Map<String, String> header = new HashMap<>();
        header.put("Authorization", "Bearer " + bearToken);
        header.put("Context-Type", "application/json");
        ResponseEntity<RhNameSpace> rhNameSpaceResponseEntity = HttpUtils.get(url, header, RhNameSpace.class);
        if (rhNameSpaceResponseEntity.getStatusCodeValue() == 200) {
            return rhNameSpaceResponseEntity.getBody();
        }
        return null;
    }

    @Override
    @SneakyThrows
    public boolean createCluster(String clusterName, String portRange) {
        String createClusterUrl = rhApi + "/cluster?_replace=true";
        Map<String, String> header = new HashMap<>();
        header.put("Authorization", "Bearer " + bearToken);
        header.put("Context-Type", "application/json");
        RhCluster rhCluster = new RhCluster();
        rhCluster.setName(clusterName);
        if (StringUtils.isNotBlank(portRange)) {
            RancherKubernetesEngineConfig rancherKubernetesEngineConfig = new RancherKubernetesEngineConfig();
            Services services = new Services();
            KubeApi kubeApi = new KubeApi();
            kubeApi.setServiceNodePortRange(portRange);
            services.setKubeApi(kubeApi);
            rancherKubernetesEngineConfig.setServices(services);
            rhCluster.setRancherKubernetesEngineConfig(rancherKubernetesEngineConfig);
        }
        String createClusterJsonStr = objectMapper.writeValueAsString(rhCluster);
        log.info("createClusterJsonStr is : {}", createClusterJsonStr);
        ResponseEntity<String> responseEntity = HttpUtils.postWithParams(createClusterUrl, header, createClusterJsonStr, String.class);
        if (responseEntity.getStatusCodeValue() == 201) {
            return true;
        }
        return false;
    }

    @SneakyThrows
    @Override
    public String getCmdToAddNodes(String envName, String roles) {
        String clusterRegistrationTokenUrl = rhApi + "/clusterregistrationtoken";
        Map<String, String> header = new HashMap<>();
        header.put("Authorization", "Bearer " + bearToken);
        header.put("Context-Type", "application/json");
        RhProject project = this.getProject(envName);
        String clusterId = project.getClusterId();
        ClusterRegistrationToken clusterRegistrationToken = new ClusterRegistrationToken();
        clusterRegistrationToken.setClusterId(clusterId);
        String clusterRegistrationTokenJsonStr = objectMapper.writeValueAsString(clusterRegistrationToken);
        log.info("clusterRegistrationTokenJsonStr is : {}", clusterRegistrationTokenJsonStr);
        ResponseEntity<ClusterRegistrationTokenResponse> responseEntity =
                HttpUtils.postWithParams(clusterRegistrationTokenUrl, header, clusterRegistrationTokenJsonStr, ClusterRegistrationTokenResponse.class);
        if (responseEntity.getStatusCodeValue() == 201) {
            Map<String, String> result = new HashMap<>();
            String nodeCommand = responseEntity.getBody().getNodeCommand();
            String[] roleArr = roles.split(",");
            for (int i = 0; i < roleArr.length; i++) {
                nodeCommand += " --" + roleArr[i];
            }
            result.put("nodeCmd", nodeCommand);
            return objectMapper.writeValueAsString(result);
        }
        return null;
    }
}
